uni-app App 开发配置
基础配置
- 默认先清除所有 android APP 权限配置,后面根据需求再配置对应的权限
- 配置 Android 平台启动时的基础权限配置为 none
- 配置支持的 CPU 类型
armeabi-v7a第 7 代及以上的 ARM 处理器(ARM32 位),市面上大多数手机使用此 CPU 类型。arm64-v8a第 8 代、64 位 ARM 处理器(ARM64 位),最近两年新发的设备使用此 CPU 类型,可以兼容使用armeabi-v7a的 so 库。
- 配置 Android 平台隐私与政策提示框
- 禁用启动界面等待雪花
- 国际化配置
// manifest.json
{
"app-plus": {
"distribute": {
/* android打包配置 */
"android": {
// 默认清除所有权限
"permissions": [],
// 不自动添加第三方SDK需要的Android权限
"autoSdkPermissions": false,
// 支持的CPU类型
"abiFilters": ["armeabi-v7a", "arm64-v8a"],
// Android平台应用启动时申请读写手机存储权限策略
"permissionExternalStorage": {
"request": "none",
"prompt": "应用保存运行状态等信息,需要获取读写手机存储(系统提示为访问设备上的照片、媒体内容和文件)权限,请允许。"
},
// Android平台应用启动时申请读取设备信息权限配置
"permissionPhoneState": {
"request": "none",
"prompt": "为保证您正常、安全地使用,需要获取设备识别码(部分手机提示为获取手机号码)使用权限,请允许。"
}
}
},
"splashscreen": {
// 禁用启动界面等待雪花
"waiting": false
}
},
// 默认返回语言
"fallbackLocale": "zh-Hans",
// 默认语言
"locale": "zh-Hans"
}
Android 平台隐私与政策提示框
{
"version": "1",
"prompt": "template",
"title": "服务协议和隐私政策",
"message": " 请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/> 你可阅读<a href=\"\">《服务协议》</a>和<a href=\"\">《隐私政策》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
"buttonAccept": "同意并接受",
"buttonRefuse": "暂不同意",
"hrefLoader": "system|default",
"second": {
"title": "确认提示",
"message": " 进入应用前,你需先同意<a href=\"\">《服务协议》</a>和<a href=\"\">《隐私政策》</a>,否则将退出应用。",
"buttonAccept": "同意并继续",
"buttonRefuse": "退出应用"
},
"disagreeMode": {
"visitorEntry": true
},
"styles": {
"backgroundColor": "#00FF00",
"borderRadius": "5px",
"title": {
"color": "#ff00ff"
},
"buttonAccept": {
"color": "#ffff00"
},
"buttonRefuse": {
"color": "#00ffff"
},
"buttonVisitor": {
"color": "#00ffff"
}
}
}
游客模式
- 在
Android 平台隐私与政策提示框中配置了visitorEntry( HX 3.6.7 版本后支持)后,会有一个游客模式的入口,后续登录等情况就需要引导用户同意隐私政策 - disagreeMode 模式限制 uni API 和组件
- 可以使用
plus.runtime.isAgreePrivacy()判断用户是否同意隐私政策 - 可以在需要的地方(如登录)引入下列代码引导用户同意隐私政策
// showPrivacyModal.js
export default () => {
return new Promise((resolve, reject) => {
// #ifdef APP-PLUS
// 用户已同意隐私政策,IOS不需要隐私与政策提示框
if (
uni.getSystemInfoSync().osName === "ios" ||
plus.runtime.isAgreePrivacy()
) {
resolve(true);
return;
}
const options = {
success: (response) => {
// 用户同意隐私政策
if (response.code === 1) {
// 如果项目中使用了 map、push、Statistic,或者设置loadNativePlugins为false时,用户选择同意隐私政策协议后需要调用plus.runtime.restart重启应用才能生效!
uni.showModal({
title: "提示",
content: "请手动重启应用,并授权相关权限!",
showCancel: false,
confirmText: "重启应用",
success: (res) => {
if (res.confirm) {
plus.runtime.restart();
}
},
});
} else if (response.code === -1) {
// 用户选择退出应用
uni.showModal({
title: "提示",
content: "如需退出应用,请手动退出!",
showCancel: false,
success: () => {
if (getCurrentPages().length > 1) {
// 返回上一页
uni.navigateBack({
delta: 1,
});
} else {
// 回到首页
uni.reLaunch({
url: "",
});
}
},
});
} else {
//用户未同意隐私政策,进入游客模式
// plus.runtime.restart();
// 回到首页
uni.reLaunch({
url: "",
});
}
},
fail: (response) => {
console.log("fail " + JSON.stringify(response));
},
};
//弹出隐私政策协议框,引导用户同意隐私政策
plus.runtime.showPrivacyDialog(options);
reject(false);
// #endif
// #ifndef APP-PLUS
resolve(true);
// #endif
});
};
// 使用示例
import showPrivacyModal from './showPrivacyModal';
async demo(){
await showPrivacyModal()
}
安全问题
manifest.json 相关安全问题修复
- 由于 App 的安装包都可以解压。前端资源,一般都是明文存放在安装包中,为防止解压后泄露敏感信息或被利用漏洞信息,所以需要进行安全处理与配置。
- Android 配置
minSdkVersion最低版本为21,对应Android5.0版本,5.0 以下版本有一些基础的隐性安全漏洞,例如:WebView远程代码执行漏洞 - iOS
js/nvue文件的原生混淆支持配置,只开发 Android 平台的应用可以不用配置以下两点配置,直接配置resources信息- 配置
supportWKWebview为true,用于支持WKWebview - 配置 iOS 支持的最低版本
deploymentTarget为11.0(iOS 平台 WKWebview 需 iOS11+系统才支持原生混淆)
- 配置
- Webview 绕过证书校验漏洞 及 Android 主机名\证书弱校验风险的问题解决,配置
untrustedca为refuse,untrustedca 属性值域说明如下accept: 接受此非受信证书,继续访问refuse: 拒绝此非受信证书,停止访问warning: 弹出警告提示框提醒用户,由用户确定是否继续访问,仅针对 webview 内部请求
// manifest.json
{
"app-plus": {
"optimization": {
// 是否开启分包优化
"subPackages": true
},
// 开启分包优化后,必须配置资源释放模式
"runmode": "liberate",
// Webview绕过证书校验漏洞 及 Android主机名\证书弱校验风险修复
"ssl": {
"untrustedca": "refuse"
},
// js/nvue文件的原生混淆
"confusion": {
"description": "原生混淆",
"supportWKWebview": true,
// resource下的键名为js文件路径(相对于应用根目录),值为空JSON对象(大括号)
"resources": {
// 示例,项目根目录下,js 文件夹内的 common.js 文件
"js/common.js": {},
// cli项目的根目录为 src 文件夹,例如 src/js/test.js 文件,加密时从js文件夹开始算
"js/test.js": {}
}
},
"distribute": {
/* android打包配置 */
"android": {
// 配置 Android平台最低支持版本为 Android5.0
"minSdkVersion": 21
},
/* ios打包配置 */
"ios": {
// 设置应用仅支持iOS11及以上设备
"deploymentTarget": "11.0"
}
}
}
}
应用签名未校验风险修复
- 风险描述
签名证书是对 App 开发者身份的唯一标识,如果程序未对签名证书进行校验,可能被反编译后进行二次打包使用其它签名证书重新签名。如重新签名的 App 可以正常启动,则可能导致 App 被仿冒盗版,影响其合法收入,甚至可能被添加钓鱼代码、病毒代码、恶意代码,导致用户敏感信息泄露或者恶意攻击。
- 修复方案
HBuilderX3.0.0+版本新增plus.navigator.getSignature (opens new window)方法获取 Android 平台签名证书的 SHA-1 指纹信息,在应用启动或运行时进行校验判断
- 为了防止 js 检验代码被反编译篡改,建议将签名校验代码放到独立 js 文件中并配置 js/nvue 文件原生混淆加密
// App.vue
export default {
onLaunch: function(inf) {
console.log("App Launch");
// #ifdef APP-PLUS
// 签名证书检验
var platform = uni.getSystemInfoSync.platform;
var sign = plus.navigator.getSignature();
if ("android" == platform) {
//Android平台
var sha1 = "baad093a82829fb432a7b28cb4ccf0e9f37dae58"; //修改为自己应用签名证书SHA-1值,是全小写并且中间不包含“:”符号
if (sha1 != sign) {
//证书不对时退出应用
plus.runtime.quit();
}
} else {
//iOS平台
var md5 = "a2e629f0ea915b4ed11e296a059c9a12"; //修改为自己应用Apple Bunld ID(AppID)的md5值
if (md5 != sign) {
//不进入应用或循环弹出提示框
console.log("应用被破坏,无法正常运行!");
uni.showModal({
title: "错误",
content: "应用被破坏,无法正常运行!",
showCancel: false,
});
}
}
// #endif
},
};
禁止使用模拟器
- 使用
plus.navigator.isSimulator(opens new window)用于判断当前应用是否运行在模拟器中。
iOS 系统由于苹果限制了正式打包后不能在模拟器上运行,一般不存在这种情况;Android 系统是开源的,底层代码都是公开的,因此市面上有很多 Android 模拟器,此问题比较严重。
模拟器通常是运行在 PC 上,可以利用一些自动化工具自动操作使用 App,另外模拟器是一个虚拟操作系统,可能会破坏原生系统的安全性,导致用户敏感信息泄露。
// App.vue
export default {
onLaunch: function(inf) {
console.log("App Launch");
// #ifdef APP-PLUS
// 模拟器检验
if (plus.navigator.isSimulator()) {
//弹出提示框
uni.showModal({
title: "错误",
content: "应用被不能运行到模拟器!",
showCancel: false,
complete: () => {
// 退出应用程序
plus.runtime.quit();
},
});
}
// #endif
},
};
Android apk 应用加固
为了提升 App 的安全性,推荐对安装包进行加固处理(如腾讯、360 等加固平台),对安全性有更高要求的 App 建议使用商用加固解决方案。
- 注:加固后需要重新签名,签名需要安装
jdk或jre:[安装与使用](/blogs/web/Android APPzhengshu.html#安装jdk环境)
# 重新签名命令
jarsigner -verbose -keystore filename.keystore -signedjar outputfile.apk inputfile.apk alias
命令含义
verbose:输出签名过程的详细信息-keystore:密匙证书文件位置filename:密匙证书文件名-signedjar:指定输入输出文件名outputfile.apk:签名后文件inputfile.apk:未签名文件alias:密匙证书文件的别名
APP 热更新
- 版本号比对
/**
* 对比版本号
* 支持比对 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之类的
* @param v1
* @param v2
* @returns
* v1 > v2 return 1
* v1 < v2 return -1
* v1 == v2 return 0
*/
export const compare = (v1: string = "0", v2: string = "0") => {
const normalizeVersion = (v: string) => v.split(".").map(Number);
const newV1 = normalizeVersion(v1);
const newV2 = normalizeVersion(v2);
const minLength = Math.min(newV1.length, newV2.length);
for (let i = 0; i < minLength; i++) {
if (newV1[i] > newV2[i]) return 1;
if (newV1[i] < newV2[i]) return -1;
}
if (newV1.length === newV2.length) return 0;
const longerVersion = newV1.length > newV2.length ? newV1 : newV2;
const rest = longerVersion.slice(minLength);
if (rest.some((n: number) => n > 0)) {
return newV1.length > newV2.length ? 1 : -1;
}
return 0;
};
Powered by Waline v2.15.8